﻿/*
 * Created by SharpDevelop.
 * User: Corrado Mio
 * Date: 13/06/2012
 * Time: 20:19
 * 
 * La connessione viene creata utilizzando la DbConnectionFactory
 */
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;

namespace CSharpExt.Data
{

    // ----------------------------------------------------------------------
    // DataConnection
    //  ----------------------------------------------------------------------
    
    /// <summary>
    /// Description of DataConnection.
    /// </summary>
    public class DataConnection
    {
        #region Factory Methods
        
        // Usa DbConnectionFactory
        
        public static DataConnection Create(Dictionary<String, String> args)
        {
            DbConnection conn = DbConnectionFactory.Create(null, args);
            return new DataConnection(conn, false, DbConnectionFactory.Compose(args));
        }
        
        public static DataConnection Open(Dictionary<String, String> args)
        {
            DbConnection conn = DbConnectionFactory.Open(null, args);
            return new DataConnection(conn, true, DbConnectionFactory.Compose(args));
        }
        
        #endregion
        
        #region Private Data
        
        private DbConnectionStringBuilder _args;
        
        private DbConnection _conn;
        
        private MetadataConnection _meta;
        
        private bool _opened;
        
        private List<DataCommand> _cmds = new List<DataCommand>();
        
        private List<DataTransaction> _transactions = new List<DataTransaction>();
        
        #endregion
        
        #region Constructor
        
        private DataConnection(DbConnection conn, bool justOpen, DbConnectionStringBuilder args)
        {
            _conn = conn;
            _args = args;
            _opened = justOpen;
        }
        
        #endregion
        
        #region Properties
        
        public String ConnectionString
        {
            get { return _args.ConnectionString; }
        }
        
        public bool Opened
        {
            get { return _opened; }
        }
        
        public MetadataConnection Metadata
        {
            get 
            {
                if (_meta == null)
                    _meta = new MetadataConnection(this);
                return _meta; 
            }
        }
        
        // ------------------------------------------------------------------
        
        internal DbConnection InnerConnection
        {
            get { return _conn; }
        }
        
        #endregion
        
        #region Operations
        
        public void Open()
        {
            _conn.Open();
        }
        
        public void Close()
        {
            closeCommands();
            
            _conn.Close();
        }
        
        // ------------------------------------------------------------------
        // SELECT
        // INSERT
        // UPDATE
        // DELETE
        // CREATE
        // ALTER
        // DROP
        // CALL
        
        /// <summary>
        /// Esegue unostatement SQL
        /// 
        /// I comandi del parametro hanno una forma del tipo 'SELECT * FROM t WHERE c={name}'
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public DataCommand CreateCommand(String command)
        {
            DataCommand dcmd = new DataCommand(this, command, CommandType.Text);
            dcmd.ParseCommand();
            
            addCommand(dcmd);
            
            return dcmd;
        }
        
        /// <summary>
        /// Richiama una StoredProcedure
        /// </summary>
        /// <param name="storedProcedure"></param>
        /// <returns></returns>
        public DataCommand CreateCall(String storedProcedure)
        {
            DataCommand dcmd = new DataCommand(this, storedProcedure, CommandType.StoredProcedure);
            dcmd.ParseCommand();
            
            addCommand(dcmd);
            
            return dcmd;
        }
        
        
        public DataCommand QueryTable(String tableName)
        {
            String select = String.Format("SELECT * FROM {0}", tableName);
            
            return CreateCommand(select);
        }
        
        // ------------------------------------------------------------------
        // Utilizzabile con una sitanssi del tipo
        //
        //      using(DataTransaction dt = conn.UsingTransaction(...))
        //      {
        //          ...
        //      }
        //
        
        public DataTransaction BeginTransaction()
        {
            return BeginTransaction(IsolationLevel.Serializable);
        }
        
        public DataTransaction BeginTransaction(IsolationLevel level)
        {
            DbTransaction trans = _conn.BeginTransaction(level);
            
            return new DataTransaction(this, trans);
        }
        
        public DataTransaction UsingTransaction()
        {
            return BeginTransaction(IsolationLevel.Serializable);
        }
        
        public DataTransaction UsingTransaction(IsolationLevel level)
        {
            DataTransaction dt =BeginTransaction(level);
            
            dt.Deferred = true;
            
            return dt;
        }
        
        #endregion
        
        #region Implementation
        
        private void closeCommands()
        {
            if (_cmds.Count == 0)
                return;
            
            List<DataCommand> cmds = new List<DataCommand>(_cmds);
            foreach(DataCommand dcmd in cmds)
            {
                dcmd.Close();
            }
        }
        
        private void addCommand(DataCommand dcmd)
        {
            _cmds.Add(dcmd);
        }
        
        internal void removeCommand(DataCommand dcmd)
        {
            _cmds.Remove(dcmd);
        }
        
        // ------------------------------------------------------------------
        
        private void closeTransactions()
        {
            List<DataTransaction> transactions = new List<DataTransaction>(_transactions);
            foreach(DataTransaction trans in transactions)
            {
                trans.Close();
            }
        }
        
        private void addTransaction(DataTransaction trans)
        {
            _transactions.Add(trans);
        }
        
        internal void removeTransactions(DataTransaction trans)
        {
            _transactions.Remove(trans);
        }
        
        #endregion
    }
}
